﻿/// <summary>
/// Developer: CHOOI KAH WAI
/// Last Modified: 23/10/2009
/// </summary>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading;
using System.Windows.Controls;
using System.Collections;
using ARSS.Common;
using System.Reflection;
using System.IO;
using System.Xml.Linq;
using System.Windows.Media.Media3D;
using ARSS.Components;
using ARSS.Visual;
using System.Xml;


namespace ARSS.Client
{
    /// <summary>
    /// System Core
    /// Controls entire system logic and flow
    /// </summary>
    class Core : Coordinator
    {
        #region Enumeration

        /// <summary>
        /// System state
        /// </summary>
        public enum emSTATE
        {
            emNONE, // Default value
            emINIT, // Initial state
            emMAIN  // Session started
        }

        #endregion

        #region Coordinator Implementations

        #region Functions

        public override void SubscribeCameraUpdateHandler(Coordinator.CameraUpdateHandler handler)
        {
            this.cameraEngine.CameraUpdateEvent += handler;
        }

        public override void SubscribeARUpdateHandler(Coordinator.ARUpdateHandler handler)
        {
            this.AREngine.ARUpdateEvent += handler;
        }

        public override void UnSubscribeCameraUpdateHandler(Coordinator.CameraUpdateHandler handler)
        {
            this.cameraEngine.CameraUpdateEvent -= handler;
        }

        public override void UnSubscribeARUpdateHandler(Coordinator.ARUpdateHandler handler)
        {
            this.AREngine.ARUpdateEvent -= handler;
        }

        public override void AlignCamera(double[] matrix)
        {
            this.visualEngine.AlignCamera(matrix);
        }

        #endregion

        #endregion

        #region Variables

        /// <summary>
        /// Core Singleton
        /// </summary>
        private static Core thisInstance;  
  
        /// <summary>
        /// Current system state
        /// </summary>
        private emSTATE currentState;

        /// <summary>
        /// Is system alive?
        /// </summary>
        private bool isAlive;

        #region Engine components

        private CamCom cameraEngine;
        private VisualManager visualEngine;
        private ARCom AREngine;

        #endregion

        #region Constants

        private const int screenWidth = 640;
        private const int screenHeight = 480;
        private const int cameraFrameRate = 30;

        #endregion

        #endregion

        #region Properties

        /// <summary>
        /// Get Core Singleton
        /// </summary>
        public static Core Instance
        {
            get
            {
                if (thisInstance == null)
                {
                    thisInstance = new Core();
                }
                return thisInstance;
            }
        }

        /// <summary>
        /// Current System State
        /// </summary>
        public emSTATE CurrentState
        {
            get
            {
                return this.currentState;
            }
            set
            {
                Logger.Instance.Log("Changing state to " + value.ToString());

                

                // Do state changing process
                switch (value)
                {
                    case emSTATE.emINIT:
                        // Is system returning from a session?
                        if (this.currentState == emSTATE.emMAIN)
                            StopPresentation();
                        break;
                    case emSTATE.emMAIN:
                        
                        break;
                }

                this.currentState = value;
                this.visualEngine.ChangeState(value);

                Logger.Instance.Log("State changed.");
            }
        }

        /// <summary>
        /// Is system alive?
        /// </summary>
        public bool IsAlive
        {
            get
            {
                return this.isAlive;
            }
            set
            {
                this.isAlive = value;
                if (!this.isAlive)
                    Application.Current.Shutdown();   // Shutdown the application
            }
        }

        /// <summary>
        /// Scene data
        /// </summary>
        public SceneDef SceneData { get; set; }


        /// <summary>
        /// Holds current user data
        /// </summary>
        public ClientData MyData { get; set; }

        #endregion

        #region Functions

        /// <summary>
        /// Constructor
        /// </summary>
        private Core()
        {
            // Initialize engine components
            this.cameraEngine = new CamCom();
            this.visualEngine = new VisualManager();
            this.AREngine = new ARCom();

            SceneData = new SceneDef();

            MyData = new ClientData();

            this.currentState = emSTATE.emNONE;
            this.isAlive = true;
        }

        /// <summary>
        /// Initialization
        /// </summary>
        public void Init()
        {
            string curDir = Directory.GetCurrentDirectory();
            // Load Settings XML
            XElement components = XElement.Load(curDir + "\\settings.xml");
            string ARComPath = components.Element("AR").Value;
            string CamComPath = components.Element("Cam").Value;

            Assembly asm = null;
            Type[] typeAry = null;

            // Load AR Engine component
            try
            {
                asm = Assembly.LoadFile(curDir + "\\" + ARComPath);
                typeAry = asm.GetTypes();
                foreach (Type t in typeAry)
                {
                    if (t.BaseType == typeof(ARCom))
                    {
                        this.AREngine = (ARCom)Activator.CreateInstance(t);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.Log("Could not load plugin " + ARComPath + ". Using default AR Component");
            }


            // Load Camera Engine component
            this.cameraEngine = new CamCom();
            try
            {
                asm = Assembly.LoadFile(curDir + "\\" + CamComPath);
                typeAry = asm.GetTypes();
                foreach (Type t in typeAry)
                {
                    if (t.BaseType == typeof(CamCom))
                    {
                        this.cameraEngine = (CamCom)Activator.CreateInstance(t);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.Log("Could not load plugin " + CamComPath + ". Using default Camera Component");
            }

        }

        /// <summary>
        /// Start presentation session
        /// </summary>
        public void StartPresentation()
        {
            try
            {
                // Initialize Camera
                this.cameraEngine.Init(screenWidth, screenHeight, cameraFrameRate);

                // Initialize Virtual Object Manager
                this.visualEngine.StartPresentation();

                // Initialize AR engine
                this.AREngine.Init(GetCamVideoInfo().Width, GetCamVideoInfo().Height, SceneData.BoardPath, SceneData.ActionsPath, this, GetCamVideoInfo());

                // All the initializations are done, start capturing video now
                this.cameraEngine.StartCapture();
            }
            catch (Exception ex)
            {
                Logger.Instance.Log("StartPresentation() failed. Reason: " + ex.Message);
                CurrentState = emSTATE.emMAIN;
            }
        }

        /// <summary>
        /// Stop presentation session
        /// </summary>
        public void StopPresentation()
        {
            this.AREngine.Destroy(this);
            this.cameraEngine.StopCapture();
        }

        /// <summary>
        /// Main window closed event
        /// </summary>
        /// <param name="w">The window</param>
        public void OnWindowClosed(Window w)
        {
            if (this.currentState == emSTATE.emINIT)
                IsAlive = false;
        }

        #region Camera Engine related functions

        public void SelectCamDevice(int selection)
        {
            this.cameraEngine.SetSelectedIndex(selection);
        }

        public string[] GetCamDevicesName()
        {
            return this.cameraEngine.GetCamNames();
        }

        public CamVideoInfo GetCamVideoInfo()
        {
            return this.cameraEngine.GetCamVideoInfo();
        }

        #endregion

        #region Visual Engine related functions

        public SceneNode GetCollision(double[] matrix)
        {
            return this.visualEngine.GetCollision(matrix);
        }

        public void DisplayMsg(string message)
        {
            this.visualEngine.DisplayMsg(message);
        }

        #endregion

        #endregion

    }
}
